home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / blix / IvtoGL.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  16.4 KB  |  643 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*______________________________________________________________________
  18.  |
  19.  | IvtoGl.c - convert inventor object to gl object
  20.  |
  21.  | this does not accept general inventor files, and you shouldn't feed
  22.  | it just any file. The limitations are very strict. The two most
  23.  | restrictive are only support for objects that are indexed per vertex,
  24.  | and it doesn't follow the inventor structure.
  25.  |
  26.  | (c) 1994 frans van hoesel, Xtreme Graphics Software
  27.  |
  28. */
  29.  
  30. #include <ctype.h>
  31. #include <search.h>
  32. #include <string.h>
  33. #include <stdio.h>
  34. #include <gl/gl.h>
  35. #include <malloc.h>
  36. #include "io.h"
  37. #include "IvtoGL.h"
  38. #include "blixvect.h"
  39.  
  40. #define NUM_KEYWORDS 23
  41. #define MAXELEM 2000
  42. #define MAXEMIS 25 /* used only in fire */
  43.  
  44. Object build_object(int mat, int num, float vec[MAXELEM][3],
  45.     float punt[MAXELEM][3], int nin[MAXELEM], int cin[MAXELEM],
  46.     int ein[MAXELEM], float emis[MAXEMIS][3], int ecnt, int backmode);
  47. void smooth_normals(int cnt, float vec[MAXELEM][3], int nin[MAXELEM],
  48.     int cin[MAXELEM]) ;
  49. int matcmp(const void *a, const void *b) ;
  50.  
  51. static int last_mat_used;
  52. static int current_backmode;
  53.  
  54.  
  55. /*________________________________________________________________________
  56.  |
  57.  | read_object_file - reads the specified inventor file
  58.  |
  59. */
  60.  
  61. void read_object_file(const char *filename, int obj) {
  62.     ENTRY item, *found_item;
  63.     /* name to look for in table */
  64.  
  65.     int i = 0;
  66.     int j;
  67.     int objcnt = 0;
  68.     static int done;
  69.     static Object objects[100];
  70.     static float default_mat[21] = {
  71.     ALPHA, 0.0,
  72.     AMBIENT, 0.1, 0.1, 0.1,
  73.     DIFFUSE, 0.4, 0.4, 0.4,
  74.     EMISSION, 0.0, 0.0, 0.0,
  75.     SPECULAR, 0.0, 0.0, 0.0,
  76.     SHININESS, 0.0,
  77.     LMNULL
  78.     };
  79.     static float current_mat[21];
  80.     static float this_mat[21];
  81.     float this_vec[MAXELEM][3];
  82.     float this_pnt[MAXELEM][3];
  83.     float this_trans[3];
  84.     float this_scale[3];
  85.     int this_axis[3];
  86.     int this_rot;
  87.     float this_angle[3];
  88.     float this_crease;
  89.     int this_cin[MAXELEM];
  90.     int this_nin[MAXELEM];
  91.     int this_ein[MAXELEM];
  92.     float this_emis[MAXEMIS][3];
  93.     static int vcnt, pcnt, ccnt, ncnt, ecnt, eicnt;
  94.     static char *s;
  95.     static int object_is_open;
  96.     static int mat;
  97.     static int backface_mode;
  98.     
  99.     
  100.     /* create table, it's a bit silly that I do this every time, but 
  101.      * this routine is only called a few times
  102.      */
  103.     hcreate(NUM_KEYWORDS);
  104.     item.key = "ambientColor";    item.data = (char *) 1; hsearch(item, ENTER);
  105.     item.key = "diffuseColor";    item.data = (char *) 2; hsearch(item, ENTER);
  106.     item.key = "specularColor";    item.data = (char *) 3; hsearch(item, ENTER);
  107.     item.key = "emissiveColor";    item.data = (char *) 4; hsearch(item, ENTER);
  108.     item.key = "shininess";    item.data = (char *) 5; hsearch(item, ENTER);
  109.     item.key = "transparency";    item.data = (char *) 6; hsearch(item, ENTER);
  110.     item.key = "vector";    item.data = (char *) 7; hsearch(item, ENTER);
  111.     item.key = "coordIndex";    item.data = (char *) 8; hsearch(item, ENTER);
  112.     item.key = "normalIndex";    item.data = (char *) 9; hsearch(item, ENTER);
  113.     item.key = "point";        item.data = (char *)10; hsearch(item, ENTER);
  114.     item.key = "end";        item.data = (char *)11; hsearch(item, ENTER);
  115.     item.key = "Separator";    item.data = (char *)12; hsearch(item, ENTER);
  116.     item.key = "hints";        item.data = (char *)13; hsearch(item, ENTER);
  117.     item.key = "translation";    item.data = (char *)14; hsearch(item, ENTER);
  118.     item.key = "axis";        item.data = (char *)15; hsearch(item, ENTER);
  119.     item.key = "angle";        item.data = (char *)16; hsearch(item, ENTER);
  120.     item.key = "scaleFactor";    item.data = (char *)17; hsearch(item, ENTER);
  121.     item.key = "creaseAngle";    item.data = (char *)18; hsearch(item, ENTER);
  122.     item.key = "materialIndex";    item.data = (char *)19; hsearch(item, ENTER);
  123.     last_mat_used = -2;
  124.     current_backmode = TRUE;
  125.     backface_mode = TRUE;
  126.     vzero(this_trans);
  127.     vset(this_scale, 1, 1, 1);
  128.     this_axis[0] = 'X';
  129.     this_axis[1] = 'X';
  130.     this_axis[2] = 'X';
  131.     this_angle[0] = 0;
  132.     this_angle[1] = 0;
  133.     this_angle[2] = 0;
  134.     this_crease = 2.0;
  135.     this_rot = 0;
  136.     open_file(filename);
  137.     for (i=0; i< 21; i++) {
  138.     this_mat[i] = default_mat[i];
  139.     current_mat[i] = default_mat[i];
  140.     }
  141.     done = FALSE;
  142.     object_is_open = FALSE;
  143.     do {
  144.     s = accept_str();
  145.     if (!(isalpha(*s))) {
  146.         skip_line();
  147.         continue;
  148.     }
  149.     item.key = s;
  150.     found_item = hsearch(item, FIND);
  151.     if (found_item == NULL)
  152.         continue;
  153.     switch((int) found_item->data) {
  154.         case 1:            /* ambientColor */
  155.         this_mat[3] = accept_float();
  156.         this_mat[4] = accept_float();
  157.         this_mat[5] = accept_float();
  158.         if (read_ch('~') == 0) {
  159.             this_mat[3] = 0.2;
  160.             this_mat[4] = 0.2;
  161.             this_mat[5] = 0.2;
  162.         }
  163.         break;
  164.         case 2:            /* diffuseColor */
  165.         this_mat[7] = accept_float();
  166.         this_mat[8] = accept_float();
  167.         this_mat[9] = accept_float();
  168.         if (read_ch('~') == 0) {
  169.             this_mat[7] = 0.8;
  170.             this_mat[8] = 0.8;
  171.             this_mat[9] = 0.8;
  172.         }
  173.         break;
  174.         case 3:            /* specularColor */
  175.         this_mat[15] = accept_float();
  176.         this_mat[16] = accept_float();
  177.         this_mat[17] = accept_float();
  178.         if (read_ch('~') == 0) {
  179.             this_mat[15] = 0.0;
  180.             this_mat[16] = 0.0;
  181.             this_mat[17] = 0.0;
  182.         }
  183.         break;
  184.         case 4:            /* emissiveColor */
  185.         ecnt = 0;
  186.         if (read_ch('[')) {
  187.             this_mat[11] = accept_float();
  188.             this_mat[12] = accept_float();
  189.             this_mat[13] = accept_float();
  190.             if (read_ch('~') == 0) {
  191.             this_mat[11] = 0.0;
  192.             this_mat[12] = 0.0;
  193.             this_mat[13] = 0.0;
  194.             }
  195.         } else {
  196.             while (read_ch(']')) {
  197.             this_emis[ecnt][0] = accept_float();
  198.             this_emis[ecnt][1] = accept_float();
  199.             this_emis[ecnt][2] = accept_float();
  200.             read_ch(',');
  201.             ecnt++;
  202.             if (ecnt == MAXEMIS) {
  203.                 errormsg("too many emissive values");
  204.             }
  205.             }
  206.             this_mat[11] = this_emis[0][0];
  207.             this_mat[12] = this_emis[0][1];
  208.             this_mat[13] = this_emis[0][2];
  209.         }
  210.         break;
  211.         case 5:            /* shininess */
  212.         this_mat[19] = accept_float();
  213.         if (read_ch('~') == 0) {
  214.             this_mat[19] = 0.0;
  215.         }
  216.         break;
  217.         case 6:            /* transparency */
  218.         this_mat[1] = accept_float();
  219.         if (read_ch('~') == 0) {
  220.             this_mat[1] = 0.0;
  221.         }
  222.         break;
  223.         case 7:            /* vector */
  224.         vcnt = 0;
  225.         if (read_ch('[')) {
  226.             this_vec[vcnt][0] = accept_float();
  227.             this_vec[vcnt][1] = accept_float();
  228.             this_vec[vcnt][2] = accept_float();
  229.             
  230.         } else {
  231.             while (read_ch(']')) {
  232.             this_vec[vcnt][0] = accept_float();
  233.             this_vec[vcnt][1] = accept_float();
  234.             this_vec[vcnt][2] = accept_float();
  235.             read_ch(',');
  236.             vcnt++;
  237.             if (vcnt == MAXELEM) {
  238.                 errormsg("too many elements in vector object");
  239.             }
  240.             }
  241.         }
  242.         break;
  243.         case 8:            /* coordIndex */
  244.         expect_ch('[');
  245.         ccnt = 0;
  246.         while (read_ch(']')) {
  247.             this_cin[ccnt] = accept_int();
  248.             read_ch(',');
  249.             ccnt++;
  250.             if (ccnt == MAXELEM) {
  251.             errormsg("too many elements in coordindex");
  252.             }
  253.         }
  254.         object_is_open = TRUE;
  255.         break;
  256.         case 9:            /* normalIndex */
  257.         expect_ch('[');
  258.         ncnt = 0;
  259.         while (read_ch(']')) {
  260.             this_nin[ncnt] = accept_int();
  261.             read_ch(',');
  262.             ncnt++;
  263.             if (ncnt == MAXELEM) {
  264.             errormsg("too many elements in coordindex");
  265.             }
  266.         }
  267.         break;
  268.         case 10:            /* point */
  269.         expect_ch('[');
  270.         pcnt = 0;
  271.         while (read_ch(']')) {
  272.             this_pnt[pcnt][0] = accept_float();
  273.             this_pnt[pcnt][1] = accept_float();
  274.             this_pnt[pcnt][2] = accept_float();
  275.             read_ch(',');
  276.             pcnt++;
  277.             if (pcnt == MAXELEM) {
  278.             errormsg("too many elements in point object");
  279.             }
  280.         }
  281.         break;
  282.         case 11:            /* end */
  283.         done = TRUE;
  284.         /* run through */
  285.         case 12:        /* Separator */
  286.         if (object_is_open) {
  287.  
  288.             if (ccnt != ncnt || (eicnt != 0 && eicnt != ccnt)) {
  289.             errormsg("error in index count");
  290.             }
  291.             if (this_crease > 1.5) {
  292.             smooth_normals(ncnt, this_vec, this_nin,
  293.                 this_cin);
  294.             }
  295.             mat = def_material(this_mat);
  296.             objects[objcnt++] = build_object(mat, ccnt, this_vec, this_pnt,
  297.                 this_nin, this_cin, this_ein, this_emis, ecnt, backface_mode);
  298.             object_is_open = FALSE;
  299.             backface_mode = TRUE;
  300.             eicnt = 0;
  301.             ecnt = 0;
  302.             this_crease = 2.0;
  303.         }
  304.         break;
  305.         case 13:            /* SURFACE */
  306.         if (strstr(lookahead(), "SURFACE") != NULL) {
  307.             backface_mode = FALSE;
  308.         }
  309.         break;
  310.         case 14:            /* translation */
  311.         this_trans[0] = accept_float();
  312.         this_trans[1] = accept_float();
  313.         this_trans[2] = accept_float();
  314.         break;
  315.         case 15:            /* axis */
  316.         if (this_rot <= 2) { 
  317.             if (read_ch('X') == 0) {
  318.             this_axis[this_rot] = 'X';
  319.             } else if (read_ch('Y') == 0) {
  320.             this_axis[this_rot] = 'Y';
  321.             } else {
  322.             expect_ch('Z');
  323.             this_axis[this_rot] = 'Z';
  324.             }
  325.         }
  326.         break;
  327.         case 16:            /* angle */
  328.         if (this_rot <= 2) {
  329.             this_angle[this_rot++] = accept_float();
  330.         }
  331.         break;
  332.         case 17:            /* scaleFactor */
  333.         this_scale[0] = accept_float();
  334.         this_scale[1] = accept_float();
  335.         this_scale[2] = accept_float();
  336.         break;
  337.         case 18:            /* creaseAngle */
  338.         this_crease = accept_float();
  339.         break;
  340.         case 19:            /* materialIndex */
  341.         expect_ch('[');
  342.         eicnt = 0;
  343.         while (read_ch(']')) {
  344.             this_ein[eicnt] = accept_int();
  345.             read_ch(',');
  346.             eicnt++;
  347.             if (eicnt == MAXELEM) {
  348.             errormsg("too many elements in materialindex");
  349.             }
  350.         }
  351.         break;
  352.     }
  353.     } while (!done);
  354.     
  355.     /* now make all the objects in this file into one big object
  356.      * by using callobj
  357.      */
  358.     makeobj(obj);
  359.     if (this_scale[0] != 1 || this_scale[1] != 1 || this_scale[2] != 1) {
  360.     scale(this_scale[0], this_scale[1], this_scale[2]);
  361.     }
  362.     if (this_angle[0] != 0) {
  363.     rot(this_angle[0] / 3.141592 * 180, this_axis[0]);
  364.     }
  365.     if (this_angle[1] != 0) {
  366.     rot(this_angle[1] / 3.141592 * 180, this_axis[1]);
  367.     }
  368.     if (this_angle[2] != 0) {
  369.     rot(this_angle[2] / 3.141592 * 180, this_axis[2]);
  370.     }
  371.     if (this_trans[0] != 0 || this_trans[1] != 0 || this_trans[2] != 0) {
  372.     translate(this_trans[0], this_trans[1], this_trans[2]);
  373.     }
  374.     for (j = 0; j < objcnt; j++) {
  375.     callobj(objects[j]);
  376.     }
  377.     if (current_backmode != TRUE) {
  378.     backface(TRUE);
  379.     current_backmode = TRUE;
  380.     }
  381.     closeobj();
  382.     hdestroy();
  383.     close_file();
  384. }
  385.  
  386.  
  387. /*_________________________________________________________________________
  388.  |
  389.  | smooth_normals - add all normals together
  390.  |
  391.  | works (well, kind of works) by adding all normals together that belong
  392.  | to some given point, and normalizing the result.
  393.  |
  394. */
  395.  
  396. void smooth_normals(int cnt, float vec[MAXELEM][3], int nin[MAXELEM],
  397.     int cin[MAXELEM]) {
  398.     
  399.     float norml[MAXELEM][3];
  400.     int i,k;
  401.     
  402.     for (i=0; i< cnt; i++) {
  403.      norml[i][0] = 0.0;
  404.      norml[i][1] = 0.0;
  405.      norml[i][2] = 0.0;
  406.     }
  407.     for (i = 0; i< cnt; i++) {
  408.     k = cin[i];
  409.     /* if (k > cnt) errormsg("wrong k"); */
  410.     if (k == -1) continue;
  411.     vadd(norml[k], vec[nin[i]], norml[k]);
  412.      
  413.     }
  414.     for (i=0; i< cnt; i++) {
  415.     k = cin[i];
  416.     /* if (k > cnt) errormsg("wrong k"); */
  417.     if (k == -1) continue;
  418.     vnormal2(norml[k], vec[cin[i]]);
  419.     nin[i] = cin[i];
  420.     }    
  421. }
  422.  
  423. /*_________________________________________________________________________
  424.  |
  425.  | matcmp - compare the materials
  426.  |
  427. */
  428.  
  429. int matcmp(const void *a, const void *b) {
  430.     return memcmp(a, b, 21 * sizeof(float));
  431. }
  432.  
  433.  
  434. /*_________________________________________________________________________
  435.  |
  436.  | def_material - define a material
  437.  |
  438.  | if the material has been previously defined, then use that, otherwise
  439.  | do a lmdef, and return the result
  440.  |
  441. */
  442.  
  443. int def_material(float *set_mat) {
  444.     static float *materials = NULL;
  445.     float *p;
  446.     static unsigned int mat_cnt = 0;
  447.     int cnt;
  448.     int ret;
  449.  
  450.     if (materials == NULL) {
  451.     materials = (float*)malloc(sizeof(float)*21);
  452.     }
  453.     cnt = mat_cnt;
  454.     p = (float *)lsearch(set_mat, materials, &mat_cnt, 21*sizeof(float), matcmp);
  455.     ret = (p - materials) / 21 +100;
  456.     if (cnt != mat_cnt) {
  457.     materials = (float*)realloc(materials, (mat_cnt+1) * sizeof(float)*21);
  458.     lmdef(DEFMATERIAL, ret, 21, set_mat);
  459.     }
  460.     return ret;
  461.     
  462. }
  463.  
  464.  
  465. /*_________________________________________________________________________
  466.  |
  467.  | sumcmp - function needed in lsearch, for comparing to ints
  468.  |
  469. */
  470.  
  471. int sumcmp(const void *a, const void *b) {
  472.     return *((const int *)a) - *((const int *)b);
  473. }
  474.  
  475.  
  476. /*_________________________________________________________________________
  477.  |
  478.  | build_object - make a GL object from inventor data
  479.  |
  480.  | uses the data stored in the various vectors (filled by the read routine)
  481.  | and make a gl object from it. If the very crude checksum is the same as
  482.  | of a previousely created gl object, then re-use that object.
  483.  | try to suppress unneeded calls (like calling n3f when the normal
  484.  | vector didn't change at all.
  485.  |
  486. */
  487.  
  488. Object build_object(int mat, int num, float vec[MAXELEM][3],
  489.     float punt[MAXELEM][3], int nin[MAXELEM], int cin[MAXELEM],
  490.     int ein[MAXELEM], float emis[MAXEMIS][3], int ecnt, int backmode) {
  491.  
  492.     static int *checksums = NULL;
  493.     static unsigned int check_cnt = 0;
  494.     int cnt;
  495.     unsigned int sum;
  496.     int *p;
  497.     int obj;
  498.     int r1, r2, i, j, n, c, e, curremis, currnorm, qmsh;
  499.     int Ob[2];
  500.     r1 = -2; r2 = -2;
  501.     sum = 0;
  502.     currnorm = -2;
  503.     curremis = -2;
  504.     sum = (int ) (punt[0][0] + punt [1][2] + punt [0][1]) *1000;
  505.     for (i=0; i< num * 3; i += 7) {
  506.     j = *((int *)punt+i);
  507.     sum = (sum ^ j )+ (j >> 4);
  508.     }
  509.     Ob[0] = sum;
  510.     Ob[1] = 0;
  511.     if ( checksums == NULL) {
  512.     checksums = (int *)malloc(sizeof(int)*2);
  513.     }
  514.     cnt = check_cnt;
  515.     p = (int *)lsearch(Ob, checksums, &check_cnt, 2 * sizeof(int), sumcmp);
  516.     obj = (p - checksums) / 2 + 10000;
  517.     if (cnt != check_cnt) {
  518.     checksums = (int*)realloc(checksums,(check_cnt+1) * sizeof(int) * 2);
  519.     makeobj(obj);
  520.     if (last_mat_used != mat) {
  521.         last_mat_used = mat;
  522.         lmbind(MATERIAL, mat);
  523.     }
  524.     if (current_backmode != backmode) {
  525.         backface(backmode);
  526.         current_backmode = backmode;
  527.     }
  528.     if (ecnt != 0) {
  529.         lmcolor(LMC_EMISSION);
  530.     }
  531.     i = 0;
  532.     qmsh = 0;
  533.     while (i < num) {
  534.         if (cin[i+3] == -1) {
  535.         /* it is a triangle */
  536.         if (qmsh) {
  537.             endqstrip();
  538.             r1 = -2;
  539.             r2 = -2;
  540.             qmsh = 0;
  541.         }
  542.         bgntmesh();
  543.         if (ecnt > 0) {
  544.             e = ein[i];
  545.             if (e != curremis) {
  546.             RGBcolor((short)(emis[e][0] * 255),
  547.                 (short)(emis[e][1] * 255),
  548.                 (short)(emis[e][2] * 255));
  549.             curremis = e;
  550.             }
  551.         }
  552.         n = nin[i]; c = cin[i]; 
  553.         if (n != currnorm) {
  554.             n3f(vec[n]);
  555.             currnorm = n;
  556.         }
  557.         v3f(punt[c]);
  558.         i++;
  559.         n = nin[i]; c = cin[i];
  560.         if (ecnt > 0) {
  561.             e = ein[i];
  562.             if (e != curremis) {
  563.             RGBcolor((short)(emis[e][0] * 255),
  564.                 (short)(emis[e][1] * 255),
  565.                 (short)(emis[e][2] * 255));
  566.             curremis = e;
  567.             }
  568.         }
  569.         if (n != currnorm) {
  570.             n3f(vec[n]);
  571.             currnorm = n;
  572.         }
  573.         v3f(punt[c]);
  574.         i++;
  575.         if (ecnt > 0) {
  576.             e = ein[i];
  577.             if (e != curremis) {
  578.             RGBcolor((short)(emis[e][0] * 255),
  579.                 (short)(emis[e][1] * 255),
  580.                 (short)(emis[e][2] * 255));
  581.             curremis = e;
  582.             }
  583.         }
  584.         n = nin[i]; c = cin[i];
  585.         if (n != currnorm) {
  586.             n3f(vec[n]);
  587.             currnorm = n;
  588.         }
  589.         v3f(punt[c]);
  590.         i+=2;
  591.         endtmesh();
  592.         } else if (cin[i+4] == -1) {
  593.         if (r1 != cin[i] || r2 != cin[i+1]) {
  594.             if (qmsh)
  595.             endqstrip();
  596.             bgnqstrip();
  597.             n = nin[i]; c = cin[i];
  598.             if (n != currnorm) {
  599.             n3f(vec[n]);
  600.             currnorm = n;
  601.             }
  602.             v3f(punt[c]);
  603.             i++;
  604.             n = nin[i]; c = cin[i];
  605.             if (n != currnorm) {
  606.             n3f(vec[n]);
  607.             currnorm = n;
  608.             }
  609.             v3f(punt[c]);
  610.             i++;
  611.         } else {
  612.             i+=2;
  613.         }
  614.         n = nin[i+1]; c = cin[i+1];
  615.         if (n != currnorm) {
  616.             n3f(vec[n]);
  617.             currnorm = n;
  618.         }
  619.         v3f(punt[c]);
  620.         r1 = c;
  621.         i++;
  622.         n = nin[i-1]; c = cin[i-1];
  623.         if (n != currnorm) {
  624.             n3f(vec[n]);
  625.             currnorm = n;
  626.         }
  627.         v3f(punt[c]);
  628.         r2 = c;
  629.         i+=2;
  630.         qmsh = 1;
  631.         } else {
  632.         fprintf(stderr,"problems at i=%d\n", i);
  633.         }
  634.     }
  635.     if (qmsh)
  636.         endqstrip();
  637.     if (ecnt > 0 )
  638.         lmcolor(LMC_COLOR);
  639.     closeobj();
  640.     }
  641.     return (Object) obj;
  642. }
  643.